# -*- coding:utf-8 -*-

import os
import math
import time
import shutil
import threading
import unittest

from MyLogger import MyLogger, SIZEROTATE, TIMEROTATE
from MyException import Error, GetSizeError, MoveFileError

class Attemper(threading.Thread):
    def __init__(self, profile, fsinfo, zipfile_list):
        threading.Thread.__init__(self)
        self.profile = profile
        self.fsinfo = fsinfo
        self.zipfile_list = zipfile_list
        
        self.move_logger = MyLogger(os.path.join(profile.log_dir, "Attemper_move.log"), SIZEROTATE, profile.size_rotate_backup_num)
        self.delete_logger = MyLogger(os.path.join(profile.log_dir, "Attemper_delete.log"), SIZEROTATE, profile.size_rotate_backup_num)
        
    def run(self):
        while(True):
            #删除缓存目录中非时间子目录
            self.delete_atemporal_cache_dir()
            
            #删除备份目录中非时间子目录
            self.delete_atemporal_backup_dir()
            
            #移动缓存目录中数据到内存盘
            self.move_back_cache_file()
                
            #删除最早备的备份时间子目录
            self.delete_early_backup_dir()
            
            #删除过期的备份时间子目录
            self.delete_overdue_backup_dir()
                
            #删除最早的缓存时间子目录
            self.delete_early_cache_dir()
            
            #删除过期的缓存时间子目录
            self.delete_overdue_cache_dir()
                
            #清理接受文件临时目录
            self.clear_receive_tmp_dir()
                
            #清理接受缓存目录和发送异常备份目录中的空目录
            self.delete_empty_dir()
          
            time.sleep(300)
                
    def move_back_cache_file(self):
        """
        移回缓存数据到内存盘目录，继续进行分发
        """
        #获取内存盘使用率
        mem_used = self.fsinfo.mem_used
        while mem_used < self.profile.mem_free_used:
            try:
                #计算最晚时间目录
                dir_list = os.listdir(self.profile.file_cache_dir)
                if not dir_list: break
                max_time_dir = max(dir_list)
                
                #判读缓存目录是否在有效期内
                dir_time = time.mktime(time.strptime(max_time_dir, "%Y%m%d%H"))
                if (time.time() - dir_time) > (self.profile.cache_file_valid_time):
                    break
                        
                #获取内存盘大小，并计算内存盘大小的10%
                mem_size = self.fsinfo.mem_size
                usable_move_size = int(mem_size*1024*1024*0.1)
                        
                #扫描最晚时间目录中文件
                dir_path = os.path.join(self.profile.file_cache_dir, max_time_dir)
                file_list = os.listdir(dir_path)
                        
                #逐个移动缓存文件，最大只移动内存盘大小10%
                for filename in file_list:
                    try:
                        src_file = os.path.join(dir_path, filename)
                        #获取文件大小
                        try:
                            filesize = os.path.getsize(src_file)
                        except Exception, msg:
                            raise GetSizeError(msg)
                        
                        #移动文件到内存盘
                        try:
                            tmp_file = os.path.join(self.profile.receive_tmp_dir, filename)
                            if self.profile.is_unzip_file and filename.endswith(".zip"):
                                dst_file = os.path.join(self.profile.unzip_dir, "src", filename)
                                shutil.move(src_file, tmp_file)
                                os.rename(tmp_file, dst_file)     
                                self.zipfile_list.add(filename)                        
                            else:
                                dst_file = os.path.join(self.profile.work_dir, filename)
                                shutil.move(src_file, tmp_file)
                                os.rename(tmp_file, dst_file)                        
                        except Exception, msg:
                            raise MoveFileError(msg)
                        
                        #记录成功移回日志
                        self.move_logger.info("Success move back file: %s to dir: %s"%(filename, os.path.dirname(dst_file)))
                        
                        #移动总量超过内存盘大小则跳出循环
                        usable_move_size -= filesize
                        if usable_move_size < 0: break;
                    except GetSizeError, msg:
                        self.move_logger.error("Error move back file: %s cause: GetSize"%(filename))
                    except MoveFileError, msg:
                        self.move_logger.error("Error move back file: %s cause: MoveFile"%(filename))
                    except Exception, msg:
                        self.move_logger.exception("Error move back file: %s cause: Unknown"%(filename))
        
                #删除目录
                if usable_move_size >= 0:
                    shutil.rmtree(dir_path)
                    
                #更新内存盘和缓存硬盘使用率
                self.fsinfo.update_mem_info()
                self.fsinfo.update_cache_hd_info()
                mem_used = self.fsinfo.mem_used
                
            except:
                self.move_logger.exception("unknown error")
                
    def delete_atemporal_cache_dir(self):
        """
        删除缓存目录中非时间子目录
        """
        try:
            dir_list = os.listdir(self.profile.file_cache_dir)
            for dirname in dir_list:
                if (not dirname.isdigit()) or (len(dirname) != 10):
                    dir_path = os.path.join(self.profile.file_cache_dir, dirname)
                    shutil.rmtree(dir_path)
                    self.delete_logger.info("Success delete cache dir: %s cause: NoTime"%(dir_path))
        except:
            self.delete_logger.exception("Error while delete notime cache dir")
        
    def delete_early_cache_dir(self):
        """
        当缓存硬盘使用率超过最大值时，删除最早时间目录
        """
        #获取缓存硬盘使用率
        cache_hd_used = self.fsinfo.cache_hd_used
        while cache_hd_used > self.profile.cache_hd_max_used:
            try:
                #计算最早时间目录
                dir_list = os.listdir(self.profile.file_cache_dir)
                if not dir_list: break
                min_time_dir = min(dir_list)
                        
                #删除最早时间目录
                dir_path = os.path.join(self.profile.file_cache_dir, min_time_dir)
                shutil.rmtree(dir_path)
                        
                self.delete_logger.info("Success delete cache dir: %s cause: MaxUsed"%(dir_path))
                        
                #更新缓存硬盘使用率
                self.fsinfo.update_cache_hd_info()
                cache_hd_used = self.fsinfo.cache_hd_used  
            except: 
                self.delete_logger.exception("Error while delete early cache dir")
                
    def delete_overdue_cache_dir(self):
        """
        删除过期的缓存文件，直接删除缓存文件目录
        """
        try:
            dir_list = os.listdir(self.profile.file_cache_dir)
            for dirname in dir_list:
                dir_time = time.mktime(time.strptime(dirname, "%Y%m%d%H"))
                if time.time() - dir_time > self.profile.cache_file_max_time:
                   dir_path = os.path.join(self.profile.file_cache_dir, dirname)
                   shutil.rmtree(dir_path)
                   self.delete_logger.info("Success delete cache dir: %s cause: MaxTime"%(dir_path))
        except:
            self.delete_logger.exception("Error while delete overdue cache dir")
        
    def delete_atemporal_backup_dir(self):
        """
        删除备份目录中非时间二级子目录
        """
        try:
            dir_list = os.listdir(self.profile.file_backup_dir)
            for dir in dir_list:
                subdir_list = os.listdir(os.path.join(self.profile.file_backup_dir, dir))
                for subdir in subdir_list:
                    if (not subdir.isdigit()) or (len(subdir) != 10):
                        dst_path = os.path.join(self.profile.file_backup_dir, dir, subdir)
                        shutil.rmtree(dst_path)
                        self.delete_logger.info("Success delete backup dir: %s cause: NoTime"%(dst_path))
        except:
            self.delete_logger.exception("Error while delete notime backup dir")
                
    def delete_early_backup_dir(self):
        """
        当备份硬盘使用率超过最大值时，删除备份目录中最早的数据
        """
        #获取备份硬盘使用率
        backup_hd_used = self.fsinfo.backup_hd_used
        while backup_hd_used > self.profile.backup_hd_max_used:
            try:
                #计算最早时间目录
                dir_list = os.listdir(self.profile.file_backup_dir)   
                min_time_dir = ""
                dir_path = ""
                for dir in dir_list:
                    subdir_list = os.listdir(os.path.join(self.profile.file_backup_dir, dir))
                    if not subdir_list: continue
                    tmp_min_time_dir = min(subdir_list)
                    if min_time_dir > tmp_min_time_dir or min_time_dir == "":
                        min_time_dir = tmp_min_time_dir
                        dir_path = os.path.join(self.profile.file_backup_dir, dir, tmp_min_time_dir)

                if not min_time_dir: break
            
                #删除最早时间目录
                shutil.rmtree(dir_path)
                
                self.delete_logger.info("Success delete backup dir: %s cause: MaxUsed"%(dir_path))
                
                #更新备份硬盘使用率
                self.fsinfo.update_backup_hd_info()
                backup_hd_used = self.fsinfo.backup_hd_used
            except:
                self.delete_logger.exception("Error while delete early backup dir")
 
    def delete_overdue_backup_dir(self):
        """
        删除备份目录中过期的二级子目录
        """
        try:
            dir_list = os.listdir(self.profile.file_backup_dir)
            for dir in dir_list:
                subdir_list = os.listdir(os.path.join(self.profile.file_backup_dir, dir))
                for subdir in subdir_list:
                    subdir_time = time.mktime(time.strptime(subdir, "%Y%m%d%H"))
                    if time.time() - subdir_time > self.profile.backup_file_max_time:
                        dst_path = os.path.join(self.profile.file_backup_dir, dir, subdir)
                        shutil.rmtree(dst_path)
                        self.delete_logger.info("Success delete backup dir: %s cause: MaxTime"%(dst_path))
        except:
            self.delete_logger.exception("Error while delete overdue backup dir")
        
    def clear_receive_tmp_dir(self):
        """
        删除接受目录临时文件
        """
        current_time = time.time()
        file_list = os.listdir(self.profile.receive_tmp_dir)
        
        for filename in file_list:
            try:
                full_path = os.path.join(self.profile.receive_tmp_dir, filename)
                modify_time = os.path.getmtime(full_path)
                file_size = os.path.getsize(full_path)
                if current_time - modify_time > self.profile.temp_file_max_time:
                    os.remove(full_path)
                    self.delete_logger.info("Success delete receive file: %s cause: OverTime"%(full_path))
                elif file_size > self.profile.file_max_size:
                    os.remove(full_path)
                    self.delete_logger.info("Success delete receive file: %s cause: BigFile"%(full_path))
                else:
                    pass
            except:
                self.delete_logger.exception("Error delete receive file: %s"%(full_path))
            
    def delete_empty_dir(self):
        """
        清除接受缓存目录和发送异常备份目录中空目录
        """
        try:
            #获取当前小时
            cur_time_dir = time.strftime("%Y%m%d%H", time.localtime())
            
            #清除接受缓存目录中的空目录
            dir_list = os.listdir(self.profile.file_cache_dir)
            for dir in dir_list:
                dir_path = os.path.join(self.profile.file_cache_dir, dir)
                if not os.listdir(dir_path) and dir != cur_time_dir:
                    shutil.rmtree(dir_path)
                    self.delete_logger.info("Success delete empty dir: %s"%(dir_path))
             
            #清除发送异常备份目录中的空目录
            dir_list = os.listdir(self.profile.file_backup_dir)
            for dir in dir_list:
                subdir_list = os.listdir(os.path.join(self.profile.file_backup_dir, dir))
                for subdir in subdir_list:
                    subdir_path = os.path.join(self.profile.file_backup_dir, dir, subdir)
                    if subdir != cur_time_dir and not os.listdir(subdir_path):
                        shutil.rmtree(subdir_path)
                        self.delete_logger.info("Success delete empty dir: %s"%(subdir_path))
        except:
            self.delete_logger.exception("Error while delete empty dir")
                              
class AttemperTestCase(unittest.TestCase):
    def setUp(self):
        self.profile = Profile()
        self.profile.PrintInfo()
        self.fsinfo = FSInfo()
        self.fsinfo.UpdateInfo()
        self.fsinfo.cache_hd_used = 95    #75, 95
        self.fsinfo.backup_hd_used = 95    #75, 95
        self.fsinfo.mem_used = 80   #40, 80
        self.fsinfo.PrintInfo()
        self.attemper = Attemper(self.profile, self.fsinfo)
        
    def tearDown(self):
        pass
    
    def testBaseFun(self):
        self.attemper.setDaemon(True)
        self.attemper.start()
        time.sleep(10)
        self.fsinfo.PrintInfo()
        
if __name__ == "__main__":
    suite = unittest.TestSuite()
    suite.addTest(AttemperTestCase("testBaseFun"))
    
    runner = unittest.TextTestRunner()
    runner.run(suite)